%{
#include "grammar.hpp"
#include <stdlib.h>
#define init_token() yylval = YYSTYPE()

extern "C"{
    int yylex();
}

using std::string;

string convertStr(const char* origin){
    string preEsc(origin);
    string postEsc = "";

    for (unsigned int i=0, j; i<preEsc.size(); ++i) {
        if (preEsc[i] != '\\') {
            postEsc.push_back(preEsc[i]);
            continue;
        }
        ++i;
        switch (preEsc[i]) {
            case 't' : {
                postEsc.push_back(char(9));
                break;
            }
            case 'r' : {
                postEsc.push_back(char(13));
                break;
            }
            case 'n' : {
                postEsc.push_back(char(10));
                break;
            }
            case '0' : {
                postEsc.push_back(char(0));
                break;
            }
            default:{
                printf("Unknown escaped character: %d\n", int(preEsc[i]));
                postEsc.push_back(char(0));
                break;
            }
        }
    }

    return postEsc;
}

%}

%option noyywrap

%%
[ \t\r\n]       ;
\/\/[^\n]*      ;
\/\*([^\*^\/]*|[\*^\/*]*|[^\**\/]*)*\*\/        ;
"if"                    init_token(); puts("if"); return IF;
"else"                  init_token(); puts("else"); return ELSE;
"return"                init_token(); puts("return"); return RETURN;
"for"                   init_token(); puts("for"); return FOR;
"while"                 init_token(); puts("while"); return WHILE;
"break"                 init_token(); puts("break"); return BREAK;
"continue"              init_token(); puts("continue"); return CONTINUE;
"struct"                init_token(); puts("struct"); return STRUCT;
"class"                 init_token(); puts("class"); return CLASS;
"fun"                   init_token(); puts("fun"); return FUN;
"Void"                  init_token(); yylval.type = BasicType::VoidTy; puts("Void"); return VOID;
"Bool&"                 init_token(); yylval.isFunParaRef = true; yylval.type = BasicType::BoolTy; puts("Bool&"); return BOOLRE;
"Bool"                  init_token(); yylval.type = BasicType::BoolTy; puts("Bool"); return BOOL;
"Char&"                 init_token(); yylval.isFunParaRef = true; yylval.type = BasicType::CharTy; puts("Char&"); return CHARRE;
"Char"                  init_token(); yylval.type = BasicType::CharTy; puts("Char"); return CHAR;
"Int&"                  init_token(); yylval.isFunParaRef = true; yylval.type = BasicType::IntTy; puts("Int&"); return INTRE;
"Int"                   init_token(); yylval.type = BasicType::IntTy; puts("Int"); return INT;
"Float&"                init_token(); yylval.isFunParaRef = true; yylval.type = BasicType::FloatTy; puts("Float&"); return FLOATRE;
"Float"                 init_token(); yylval.type = BasicType::FloatTy; puts("Float"); return FLOAT;
"Double&"               init_token(); yylval.isFunParaRef = true; yylval.type = BasicType::DoubleTy; ; puts("Double&"); return DOUBLERE;
"Double"                init_token(); yylval.type = BasicType::DoubleTy; ; puts("Double"); return DOUBLE;
"String&"               init_token(); yylval.isFunParaRef = true; ; puts("String&"); return STRRE;
"String"                init_token(); yylval.type = BasicType::CharTy->getPointerTo(); ; puts("String"); return STR;
"private"               init_token(); puts("PRIVATE"); return PRIVATE;
"public"                init_token(); puts("PUBLIC"); return PUBLIC;
"protected"             init_token(); puts("PROTECTED"); return PROTECTED;
"override"              init_token(); puts("OVERRIDE"); return OVERRIDE;
"super"                 init_token(); puts("SUPER"); return SUPER;
"as"                    init_token(); puts("AS"); return AS;
"val"                   init_token(); assert(yylval.type == nullptr && "token val should have no type"); puts("VAL"); return VAL;
"var"                   init_token(); assert(yylval.type == nullptr && "token var should have no type"); puts("VAR"); return VAR;
"true"                  init_token(); yylval.iValue = 1; puts("FJTRUE"); return FJTRUE; 
"false"                 init_token(); yylval.iValue = 0; puts("FJFALSE"); return FJFALSE;       
[a-zA-Z_][a-zA-Z0-9_]*  init_token(); yylval.content = std::string(yytext); puts("FJIDENTIFIER"); assert(yylval.content != "" && "identifier should not be empty");  return FJIDENTIFIER;
[0-9]+\.[0-9]*          init_token(); yylval.dValue = atof(yytext); puts("FJDOUBLE"); return FJDOUBLE;
[0-9]+                  init_token(); yylval.iValue = atoi(yytext); puts("FJINTEGER"); return FJINTEGER;
\'(\\.|[^"]|\\0|\\t|\\n|\\r)\'          init_token(); yylval.c = convertStr(yytext)[1]; puts("FJCHAR"); return FJCHAR;
\"(\\.|[^"])*\"         init_token(); yytext[yyleng-1]='\0'; yylval.content = convertStr(yytext+1); puts("FJSTRING"); return FJSTRING;
"="                     init_token(); yylval.op = OpType::Assign; puts("EQ"); return EQ;
"=="                    init_token(); yylval.op = OpType::Eq; puts("EQEQ"); return EQEQ;
"!="                    init_token(); yylval.op = OpType::Neq; puts("NEQ"); return NEQ;
"<"                     init_token(); yylval.op = OpType::Lt; puts("LT"); return LT;
"<="                    init_token(); yylval.op = OpType::Leq; puts("LOE"); return LOE;
">"                     init_token(); yylval.op = OpType::Gt; puts("GT"); return GT;
">="                    init_token(); yylval.op = OpType::Geq; puts("GOE"); return GOE;
"("                     init_token(); puts("LPAREN"); return LPAREN;
")"                     init_token(); puts("RPAREN"); return RPAREN;
"{"                     init_token(); puts("LBRACE"); return LBRACE;
"}"                     init_token(); puts("RBRACE"); return RBRACE;
"["                     init_token(); puts("LBRACKET"); return LBRACKET;
"]"                     init_token(); puts("RBRACKET"); return RBRACKET;
"."                     init_token(); puts("DOT"); return DOT;
","                     init_token(); puts("COMMA"); return COMMA;
":"                     init_token(); puts("COLON"); return COLON;
"+"                     init_token(); yylval.op = OpType::Add; puts("ADD"); return ADD;
"-"                     init_token(); yylval.op = OpType::Sub; puts("SUB"); return SUB;
"*"                     init_token(); yylval.op = OpType::Mul; puts("MUL"); return MUL;
"/"                     init_token(); yylval.op = OpType::Div; puts("DIV"); return DIV;
"%"                     init_token(); yylval.op = OpType::Mod; puts("MOD"); return MOD;
"++"                    init_token(); puts("SELFINC"); return SELFINC;
"--"                    init_token(); puts("SELFDEC"); return SELFDEC;
"&&"                    init_token(); yylval.op = OpType::And; ; puts("AND"); return AND;
"||"                    init_token(); yylval.op = OpType::Or; ; puts("OR"); return OR;
"!"                     init_token(); puts("NOT"); return NOT;
"^"                     init_token(); yylval.op = OpType::Xor; ; puts("XOR"); return XOR;
">>"                    init_token(); puts("SR"); return SR;
"<<"                    init_token(); puts("SL"); return SL;
";"                     init_token(); yylval.op = OpType::Semi; puts("SEMI"); return SEMI;
.                       init_token(); printf("Unknown token:%s\n", yytext); yyterminate();
%%